/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package desarrollosoft.ghce.soporte;

import desarrollosoft.ghce.dao.excepciones.ProfesionalInexistenteException;
import desarrollosoft.ghce.dao.interfaces.IProfesionalDAO;
import desarrollosoft.ghce.entidades.Profesional;
import desarrollosoft.ghce.servicio.interfaces.IServicioProfesionales;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

/**
 * A custom UserDetailsService implementation to adapt to extended User
 * class.<br>
 *
 * If you have your own user credential model and don't want to change it even a
 * bit, then instead of swapping the UserDetailService of default
 * AuthenticationProvider, you have to swap the AuthenticationProvider itself,
 * and you'll have to deal with password hashing and salting by your own.<br>
 *
 *
 * @author Joaquin Lima (Ian YT Tsai)
 *
 */
public class ServicioUsuarioSistema implements UserDetailsService {

    @Autowired
    @Qualifier("profesionalDAO")
    IProfesionalDAO profesionalDAO;
    
    @Autowired
    @Qualifier("servicioProfesionales")
    IServicioProfesionales servicioProfesionales;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        /* GUARDA: si no encontramos el usuario o hay despelote,
        tirar UsernameNotFoundException NUNCA devolver null */
        
        Profesional profesional;
        
        try {
            profesional = profesionalDAO.buscarPorNombreUsuario(username);
        } catch (ProfesionalInexistenteException e) {
            throw new UsernameNotFoundException("NO SE ENCONTRO USUARIO ServicioUsuarioSistema linea: 52");
        }
        
        // si esta con contrasenia reseteada, pongo solo por software rol "reseteado"
        // para hacer logout por software:
        // http://stackoverflow.com/questions/5727380/how-to-manually-log-out-a-user-with-spring-security
        // implementar esta interface:
        // http://docs.spring.io/spring-security/site/docs/current/apidocs/org/springframework/security/crypto/password/PasswordEncoder.html
        // para codificar el password leido:
        // http://stackoverflow.com/questions/17444258/how-to-use-new-passwordencoder-from-spring-security
        Integer rol;
        if (servicioProfesionales.estaReseteado(profesional)) {
            rol = Global.ROLE_USUARIO_RESETEADO;
        } else {
            rol = profesional.getRol();
        }
        
        UsuarioSistema usuarioSistema = new UsuarioSistema(
                profesional.getNombreUsuario(),
                profesional.getContrasenia(), 
                getAuthorities(rol)
        );

        return usuarioSistema;
    }

    /**
     * Retrieves the correct ROLE type depending on the access level, where
     * access level is an Integer. Basically, this interprets the access value
     * whether it's for a regular user or admin.
     *
     * @param access an integer value representing the access of the user
     * @return collection of granted authorities
     */
    private Collection<GrantedAuthority> getAuthorities(Integer access) {
        // Create a list of grants for this user
        List<GrantedAuthority> authList = new ArrayList<>();

        if (access.equals(Global.ROLE_USUARIO_PROFESIONAL)) {
            // Usuario solo tiene permisos de medico
            authList.add(new SimpleGrantedAuthority(Global.getRole(Global.ROLE_USUARIO_PROFESIONAL)));
            return authList;
        }
        if (access.equals(Global.ROLE_USUARIO_ADMINISTRADOR)) {
            // Usuario solo tiene permisos de Administrador
            authList.add(new SimpleGrantedAuthority(Global.getRole(Global.ROLE_USUARIO_ADMINISTRADOR)));
            return authList;
        }
        if (access.equals(Global.ROLE_USUARIO_RESETEADO)) {
            // Usuario solo tiene permisos de Usuario Reseteado
            authList.add(new SimpleGrantedAuthority(Global.getRole(Global.ROLE_USUARIO_RESETEADO)));
            return authList;
        }
        // Return list of granted authorities
        return authList;
    }
}
